﻿#region Copyright Notice
// 
// 
// Copyright (c) 2009-2010 Anindya Chatterjee
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// 
// 
// 
#endregion
using System;
using System.ComponentModel;
using System.Threading;
using Event.Plugin.Configuration;
using Event.Plugin.Utility;
using Timer=System.Windows.Forms.Timer;

namespace Event.Plugin
{
    ///<summary>
    /// Abstract condition class
    ///</summary>
    public abstract class AbstractCondition : ICondition
    {
        private readonly Timer _timer;
        private volatile bool _listened;
        private BackgroundWorker _workerThread;
        
        /// <summary>
        /// Initializes a new instance of the <see cref="AbstractCondition"/> class.
        /// </summary>
        protected AbstractCondition()
        {
            _timer = new Timer {Enabled = false, Interval = 1000};
            _timer.Tick += TimerTick;
            
            InitializeEvent();
        }

        /// <summary>
        /// Asleeps the event listening for a given interval of time.
        /// </summary>
        /// <param name="interval">an interval for which the listening will be asleep</param>
        public void Sleep(int interval)
        {
            Thread.Sleep(interval);
        }

        #region ICondition Members

        /// <summary>
        /// Put your business logic here which will execute after every ListeningInterval of time
        /// </summary>
        public abstract void EventLogic();

        /// <summary>
        /// Parent event for which this condition works
        /// </summary>
        public virtual IEvent Parent { get; set; }

        /// <summary>
        /// Returns true to the parent when the condition is satisfied, false otherwise
        /// </summary>
        public virtual bool Statisfied { get; set; }

        /// <summary>
        /// Initializes settings and all, of an event
        /// </summary>
        public virtual void InitializeEvent()
        {
        }

        bool IEvent.IsScheduled
        {
            get { return false; }
        }

        ICondition IEvent.Condition { get; set; }

        IEventHost IEvent.Host { get; set; }

        INotifier IEvent.UserNotifier { get; set; }

        IEventSettings IEvent.EventSettings { get; set; }

        ISettings IEvent.ApplicationSettings { get; set; }

        UnhandledException IEvent.UnhandledExceptionHandler { get; set; }

        string IEvent.Name { get; set; }

        bool IEvent.IsConditionSatisfied()
        {
            return false;
        }

        void IEvent.Notify()
        {
        }

        bool IEvent.Loop { get; set; }

        #endregion

        #region Implemented Memebers

        /// <summary>
        /// Event id, it should be unique
        /// </summary>
        public int Id { get; set; }

        /// <summary>
        /// The time interval for which EventLogic will be executed
        /// </summary>
        public int ListeningInterval
        {
            get { return _timer.Interval; }
            set { _timer.Interval = value; }
        }

        /// <summary>
        /// Signaled the listener that listening is completed
        /// </summary>
        public event Signal Listened;

        /// <summary>
        /// Signaled the listener that listening is completed
        /// </summary>
        /// <value></value>
        public bool ListeningComplete
        {
            get { return _listened; }
            set { _listened = value; }
        }

        /// <summary>
        /// Starts listening the EventLogic
        /// </summary>
        public void StartListening()
        {
            _timer.Enabled = true;
        }


        /// <summary>
        /// Execute it after one listening is complete
        /// </summary>
        public void EndListening()
        {
            _timer.Enabled = false;
        }

        #endregion

        /// <summary>
        /// Executes the main event logic after a regular interval of time
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void TimerTick(object sender, EventArgs e)
        {
            if (_workerThread == null)
            {
                _workerThread = new BackgroundWorker();
                _workerThread.DoWork += WorkerThreadDoWork;
                _workerThread.RunWorkerCompleted += WorkerThreadRunWorkerCompleted;
                _workerThread.RunWorkerAsync();
            }
            if (ListeningComplete)
            {
                ListeningComplete = false;
                Listened(this, new SignalArgs {Sender = this});
            }
        }

        private void WorkerThreadRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            _workerThread.Dispose();
            _workerThread = null;
        }

        private void WorkerThreadDoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                EventLogic();
            }
            catch (Exception ex)
            {
                if (Parent.UnhandledExceptionHandler != null)
                    Parent.UnhandledExceptionHandler(this, ex);
                // stop the event to be listened to
                EndListening();
                Parent.EndListening();
            }
        }
    }
}